package org.rkuk.kasutil.uintTest.framework 
{
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.TimerEvent;
	import flash.utils.Timer;
	import org.rkuk.kasutil.uintTest.event.TestEvent;
	/**
	 * ...
	 * @author rkuk
	 */
	public class AnsyTestMethod extends TestMethod 
	{
		private var ansyEventTarget_:Array;
		private var ansyEvent_:Array;
		private var ansyHandler_:Array;
		private var ansyTimeout_:Array;
		private var ansyEventParam_:Array;
		private var ansyTimer_:Array;
		private var invoker_:Object;
		
		public function AnsyTestMethod(methodName:String, isStatic:Boolean, ...params) ;
		{
			super(methodName, isStatic);
			params_ = params_;
		}
		
		public function addAnsyEvent(target:String, eventType:String, eventHandler:String, timeout:int, ...params)
		{
			if (ansyEvent_ == null)
			{
				ansyEventTarget_ = new Array();
				ansyEvent_ = new Array();
				ansyHandler_ = new Array();
				ansyTimeout_ = new Array();
				ansyEventParam_ = new Array();
				ansyTimer_ = new Array();
			}
			
			ansyEventTarget_.push(target || "this");
			ansyEvent_.push(eventType);
			ansyHandler_.push(eventHandler);
			ansyTimeout_.push(timeout);
			ansyEventParam_.push(params);
		}
		
		override public function execute(invoker:Object):void 
		{
			invoker_ = invoker;
			for (var i:int = 0; i < ansyEvent_.length;i++ )
			{
				var target:EventDispatcher;
				var warning:TestWarning;
				
				if (ansyEventTarget_[i] == "this")
					target = invoker as EventDispatcher;
				else
				{
					if (invoker.hasOwnProperty(ansyEventTarget_[i]))
					{
						var fun:Function = invoker[ansyEventTarget_[i]] as Function;
						if (fun != null)
							target = fun.apply(invoker) as EventDispatcher;
						else
							target = invoker[ansyEventTarget_[i]] as EventDispatcher;
					}
					else
					{
						warning = new TestWarning(invoker + " doesn't have " + ansyEventTarget_[i] + " property as an EventDispatch for event " + ansyEvent_[i])
						TestEnviorenment.instance.addWarning(warning);
					}
				}
				
				
				if (target != null)
				{
					if(!target.hasEventListener(ansyEvent_[i]))
						target.addEventListener(ansyEvent_[i], onAnsyMethodEvent);
					ansyEventTarget_[i] = target;
					var timer:Timer = new Timer(ansyTimeout_[i], 1);
					timer.addEventListener(TimerEvent.TIMER, onAnsyEventTimeout);
					ansyTimer_.push(timer);
				}
				else
				{
					if (warning == null)
					{
						warning = new TestWarning(ansyEventTarget_[i] + " of " + invoker + " isn't an EventDispatcher for event " + ansyEvent_[i]);
						TestEnviorenment.instance.addWarning(warning);
					}
					removeAnsy(i--);
				}
			}
				
			isSuccess_ = TestEnviorenment.instance.runTest(invoker_, methodName_, params_);
			
			for (i = 0; i < ansyTimer_.length; i++)
				Timer(ansyTimer_[i]).start();
		}
		
		private function onAnsyMethodEvent(e:Event):void
		{
			for (var i:int = 0; i < ansyEventTarget_.length; )
			{
				if (e.target == ansyEventTarget_[i] &&  e.type == ansyEvent_[i])
				{
					Timer(ansyTimer_[i]).removeEventListener(TimerEvent.TIMER, onAnsyEventTimeout);
					Timer(ansyTimer_[i]).stop();
					EventDispatcher(ansyEventTarget_[i]).removeEventListener(ansyEvent_[i], onAnsyMethodEvent);
					
					isSuccess_ = TestEnviorenment.instance.runTest(invoker_, ansyHandler_[i], ansyEventParam_[i]) && isSuccess_;
					
					removeAnsy(i);
					if (ansyEvent_.length <= 0)
						notifyExecuted();
				}
				else 
					i++;
			}
		}
		
		private function onAnsyEventTimeout(e:TimerEvent):void
		{
			var i:int = ansyTimer_.indexOf(e.target);
			Timer(ansyTimer_[i]).removeEventListener(TimerEvent.TIMER, onAnsyEventTimeout);
			EventDispatcher(ansyEventTarget_[i]).removeEventListener(ansyEvent_[i], onAnsyMethodEvent);
			
			isSuccess_ = false;
			var message:String = "Asynchronous event: " + ansyEvent_[i] + " did not fire after " + ansyTimeout_[i] + "ms";
			TestEnviorenment.instance.addFailure(new TestFailure(message));
			
			removeAnsy(i);
			if (ansyEvent_.length <= 0)
				notifyExecuted();
		}
		
		private function removeAnsy(index:int):void 
		{
			ansyEventTarget_.splice(index, 1);
			ansyEvent_.splice(index, 1);
			ansyHandler_[index].splice(index, 1);
			ansyEventParam_.splice(index, 1);
			ansyTimeout_.splice(index, 1);
			ansyTimer_.splice(index, 1);
		}
	}
}